package com.acme.clientserver;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintStream;
import java.io.UnsupportedEncodingException;
import java.net.ServerSocket;
import java.net.Socket;

import com.acme.bankapp.domain.bank.Bank;
import com.acme.bankapp.service.bank.BankDataLoaderService;
import com.acme.bankapp.service.bank.BankService;
import com.acme.bankapp.service.bank.exception.ClientLineParseException;

/**
 * Class responsible for running bank application as a server.
 * 
 */
public class BankServer {
	private static final int BACKLOG = 10;
	private static final int SERVER_PORT = 2013;

	ServerSocket socketFactory;
	Socket connection = null;
	ObjectOutputStream out;
	ObjectInputStream in;
	String message;

	/**
	 * Runs server, allowing remote clients to connect and execute a few
	 * commands.
	 * 
	 * @param bank
	 *            bank to work on
	 */
	public void startServer(Bank bank) {
		do {
			try {
				// 1. creating a server socket
				socketFactory = new ServerSocket(SERVER_PORT, BACKLOG);

				// 2. Wait for connection
				System.out.println("server> Waiting for connection...");
				connection = socketFactory.accept();
				System.out.println("server> Connection received from "
						+ connection.getInetAddress().getHostName() + ".");

				// 3. get Input and Output streams
				out = new ObjectOutputStream(connection.getOutputStream());
				in = new ObjectInputStream(connection.getInputStream());

				// 4. The two parts communicate via the input and output streams
				boolean doStop = false;
				do {
					try {
						message = (String) in.readObject();
						System.out.println("client> " + message);
						doStop = processMessage(message, bank);
					} catch (ClassNotFoundException classnot) {
						System.err.println("Data received in unknown format.");
					}
				} while (!doStop);
			} catch (IOException ioException) {
				ioException.printStackTrace();
			} finally {
				// 4: Closing connection
				try {
					in.close();
					out.close();
					socketFactory.close();
				} catch (IOException ioException) {
					ioException.printStackTrace();
				}
			}
		} while (true);
	}

	private boolean processMessage(String message, Bank bank)
			throws UnsupportedEncodingException {
		String[] parts = message.split("\\s", 2);
		String command = parts[0];
		switch (command.toUpperCase()) {
		case "SHOWCLIENTS":
		case "CLIENTLIST":
			ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
			PrintStream printStream = new PrintStream(outputStream);
			BankService.printAllClients(printStream, bank);
			String msg = outputStream.toString("UTF8");
			sendMessage(msg);
			return false;
		case "ADDCLIENT":
			try {
				String argument = parts[1];
				BankDataLoaderService.parseAndApplyClientLine(argument, bank);
				sendMessage("Client successfully added.");
			} catch (ClientLineParseException e) {
				sendMessage("Command failed. Wrong format.");
			}
			return false;
		case "BYE":
			sendMessage("bye");
			return true;
		default:
			sendMessage("Unknown command.");
			return false;
		}
	}

	private void sendMessage(final String msg) {
		try {
			out.writeObject(msg);
			out.flush();
			System.out.println("server> " + msg.trim());
		} catch (IOException ioException) {
			ioException.printStackTrace();
		}
	}
}
